﻿package lz.controls.managers
{
	
	import flash.text.TextFormat;
	import flash.utils.Dictionary;
	import flash.utils.getDefinitionByName;
	import flash.utils.getQualifiedClassName;
	import flash.utils.getQualifiedSuperclassName;
	
	import lz.controls.ToolTip;
	import lz.controls.core.UIComponent;
	
	/**
	 * StyleManager 类提供静态方法，可以用于为组件实例、整个组件类型或 Flash 文档中的所有用户界面组件获取和设置样式。 
	 * 样式定义为影响组件显示的值，包括填充、文本格式和外观。
	 */
	public class StyleManager 
	{
        /**
         * @private
         */
		private static var _instance:StyleManager;

		// Allows lookups of all classes that use a specific style:
        /**
         * @private
         */
		private var styleToClassesHash:Object;

		// Allows lookups of all instances of a specific class:
        /**
         * @private
         */
		private var classToInstancesDict:Dictionary;

        // Allows lookup of current styles for a specific class:
        /**
         * @private
         */
		private var classToStylesDict:Dictionary;

		// Allows lookup of default styles for a specific class:

        /**
         * @private
         */
        private var classToDefaultStylesDict:Dictionary;

        /**
         * @private
         */
		private var globalStyles:Object;
		
		/**
         * 创建新的 StyleManager 对象。
		 */
		public function StyleManager() 
		{
			styleToClassesHash = {};
			classToInstancesDict = new Dictionary(true);
			classToStylesDict = new Dictionary(true);
			classToDefaultStylesDict = new Dictionary(true)
			globalStyles = UIComponent.getStyleDefinition();
			TipsManager.register(ToolTip);
		}
		
		/**
         * @private
		 */
		private static function getInstance():StyleManager
		{
			if (_instance == null) 
			{ 
				_instance = new StyleManager(); 
			}
			return _instance;
		}
		
		/**
		 * 向样式管理器注册组件实例。 组件实例经过实例化后，可以向样式管理器注册，以便得到样式更改的通知。 组件实例可以注册，以便接收基于组件的或全局性质的样式更改的通知。
		 * 参数
		 * instance:UIComponent — 要进行注册以便获得样式管理的组件实例。
		 */
		public static function registerInstance(instance:UIComponent):void 
		{
			var inst:StyleManager = getInstance();
			var classDef:Class = getClassDef(instance);
			
			if (classDef == null) {	return;	}
			
			// check if an instance of this class has been registered before:
			if (inst.classToInstancesDict[classDef] == null) 
			{
				
				inst.classToInstancesDict[classDef] = new Dictionary(true);
				// set up the style to class hash. This lets us look up which classes use which styles quickly.
				var target:Class = classDef;				
				var defaultStyles:Object;
				// Walk the inheritance chain looking for a default styles object.
				while (defaultStyles == null)
				{
					// Trick the strict compiler.
					if (target["getStyleDefinition"] != null) 
					{
						defaultStyles = target["getStyleDefinition"]();
						break;
					}
					try 
					{
						target = instance.loaderInfo.applicationDomain.getDefinition(getQualifiedSuperclassName(target)) as Class;
					} catch(err:Error) 
					{
						try 
						{
							target = getDefinitionByName(getQualifiedSuperclassName(target)) as Class;
						} catch (e:Error) 
						{
							defaultStyles = UIComponent.getStyleDefinition();
							break;
						}
					}
				}
				
				var styleToClasses:Object = inst.styleToClassesHash;
				for (var n:String in defaultStyles) 
				{
					
					if (styleToClasses[n] == null) 
					{
						styleToClasses[n] = new Dictionary(true);
					}
					// add this class as a subscriber to this style:
					styleToClasses[n][classDef] = true;
				}
				// add this class's default styles:
				inst.classToDefaultStylesDict[classDef] = defaultStyles;
				if (inst.classToStylesDict[classDef] == null) 
				{
					// set up the override styles table:
					inst.classToStylesDict[classDef] = {};
				}
			}
			inst.classToInstancesDict[classDef][instance] = true;
			setSharedStyles(instance);
		}
		
		/**
		 * @private
		 */
		private static function setSharedStyles(instance:UIComponent):void 
		{
			var inst:StyleManager = getInstance();
			var classDef:Class = getClassDef(instance);
			var styles:Object = inst.classToDefaultStylesDict[classDef];
			for (var n:String in styles) 
			{
				instance.setSharedStyle(n,getSharedStyle(instance,n));
			}
		}
		
        /**
         * @private
		 */
		private static function getSharedStyle(instance:UIComponent,name:String):Object 
		{
			var classDef:Class = getClassDef(instance);
			var inst:StyleManager = getInstance();
			// first check component styles:
			var style:Object = inst.classToStylesDict[classDef][name];
			if (style != null) { return style; }
			// then check global styles:
			style = inst.globalStyles[name];
			
			if (style != null) { return style; }
			// finally return the default component style:
			return inst.classToDefaultStylesDict[classDef][name];
		}
		
		/**
		 * 获取在特定组件上存在的样式。
		 * 参数
		 * component:Object — 要在其上查找所请求样式的组件实例的名称。
		 * name:String — 要检索的样式的名称。
		 */
		public static function getComponentStyle(component:Object,name:String):Object 
		{
			var classDef:Class = getClassDef(component);
			var styleHash:Object = getInstance().classToStylesDict[classDef];
			return (styleHash == null) ? null : styleHash[name];
		}
		/**
		 * 从指定组件中删除样式。
		 * 参数
		 * component:Object — 要删除样式的组件的名称。
		 * name:String — 要删除的样式的名称。
		 */
		public static function clearComponentStyle(component:Object,name:String):void 
		{
			var classDef:Class = getClassDef(component);
			var styleHash:Object = getInstance().classToStylesDict[classDef];
			if (styleHash != null && styleHash[name] != null) 
			{
				delete(styleHash[name]);
				invalidateComponentStyle(classDef,name);
			}
		}
		
		/**
		 * 在某个组件类型的所有实例上设置样式，例如，在 Button 组件的所有实例上，或在 ComboBox 组件的所有实例上。
		 * 参数
		 * component:Object — 组件类型的例子为 Button 或 ComboBox。 此参数还接受用于标识一个组件类型的所有实例的组件实例或类。
		 * name:String — 要设置的样式的名称。
		 * style:Object — 说明要设置的样式的样式对象。
		 */
		public static function setComponentStyle(component:Object,name:String,style:Object):void 
		{
			var classDef:Class = getClassDef(component);
			var styleHash:Object = getInstance().classToStylesDict[classDef];
			if (styleHash == null)
			{
				styleHash = getInstance().classToStylesDict[classDef] = {};
			}
			if (styleHash == style) { return; }
			styleHash[name] = style;
			invalidateComponentStyle(classDef,name);
		}
		
        /**
         * @private (protected)
		 */
		private static function getClassDef(component:Object):Class 
		{
			if (component is Class)
			{ 
				return (component as Class);
			}
			try 
			{
				return getDefinitionByName(getQualifiedClassName(component)) as Class;
			} catch (e:Error)
			{
				if (component is UIComponent) 
				{
					try 
					{
						return component.loaderInfo.applicationDomain.getDefinition(getQualifiedClassName(component)) as Class;
					} catch (e:Error) {}
				}
			}
			return null;
		}
		
        /**
         * @private (protected)
		 */
		private static function invalidateStyle(name:String):void
		{
			var classes:Dictionary = getInstance().styleToClassesHash[name];
			if (classes == null) { return; }
			for (var classRef:Object in classes)
			{
				invalidateComponentStyle(Class(classRef),name);
			}
		}
		
        /**
         * @private (protected)
		 */
		private static function invalidateComponentStyle(componentClass:Class,name:String):void 
		{
			var instances:Dictionary = getInstance().classToInstancesDict[componentClass];
			if (instances == null) { return; }
			
			for (var obj:Object in instances) 
			{
				var instance:UIComponent = obj as UIComponent;
				if (instance == null) { continue; }
				instance.setSharedStyle(name,getSharedStyle(instance,name));
			}
		}
		/**
		 *为文档中的所有用户界面组件设置全局样式。
		 * 参数
		 * name:String — 命名要设置的样式的字符串值。
		 * style:Object — 要设置的样式对象。 该属性的值取决于用户设置的样式。 
		 * 例如，如果样式设置为“textFormat”，则样式属性应设置为 TextFormat 对象。 
		 * 样式名称和样式属性值之间不匹配可能会导致组件行为不正确。
		 */
		public static function setStyle(name:String, style:Object):void 
		{
			var styles:Object = getInstance().globalStyles;
			if (styles[name] === style && !(style is TextFormat)) { return; }
			styles[name] = style;
			invalidateStyle(name);
		}
		
		/**
		 *从文档中的所有用户界面组件中删除全局样式。
		 * 参数
		 * name:String — 要删除的全局样式的名称。
		 */		
		public static function clearStyle(name:String):void 
		{
			setStyle(name,null);
		}
		
		/**
		 * 按名称获取全局样式。
		 * 参数
		 * name:String — 要检索的样式的名称。
		 * 返回
		 * Object — 检索的全局样式的值。
		 */
		public static function getStyle(name:String):Object 
		{
			return getInstance().globalStyles[name];
		}
		
	}
	
}
